"""
API依赖注入
认证、权限等依赖函数
"""
from typing import Optional
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.security import verify_token, InvalidTokenException
from app.models.user import User
from app.services.user_service import user_service

# HTTP Bearer认证方案
security = HTTPBearer()


async def get_current_user(
    db: AsyncSession = Depends(get_db),
    credentials: HTTPAuthorizationCredentials = Depends(security)
) -> User:
    """
    获取当前认证用户
    Args:
        db: 数据库会话
        credentials: 认证凭据
    Returns:
        当前用户对象
    Raises:
        HTTPException: 认证失败
    """
    token = credentials.credentials
    
    # 验证令牌
    user_id = verify_token(token)
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的认证令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 获取用户
    user = await user_service.get_user_by_id(db, user_id=int(user_id))
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 检查用户是否激活
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户已被禁用",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    return user


async def get_current_active_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """
    获取当前活跃用户(别名函数，更语义化)
    Args:
        current_user: 当前用户
    Returns:
        当前用户对象
    """
    return current_user


async def get_current_admin_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """
    获取当前管理员用户
    Args:
        current_user: 当前用户
    Returns:
        管理员用户对象
    Raises:
        HTTPException: 权限不足
    """
    if current_user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="权限不足，需要管理员权限"
        )
    return current_user


async def get_current_project_manager_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """
    获取当前项目管理员用户
    Args:
        current_user: 当前用户
    Returns:
        项目管理员用户对象
    Raises:
        HTTPException: 权限不足
    """
    if current_user.role not in ["admin", "project_manager"]:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="权限不足，需要项目管理员或管理员权限"
        )
    return current_user


def require_roles(*roles: str):
    """
    角色权限装饰器工厂
    Args:
        *roles: 允许的角色列表
    Returns:
        权限检查依赖函数
    """
    async def check_role(current_user: User = Depends(get_current_user)) -> User:
        if current_user.role not in roles:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"权限不足，需要以下角色之一: {', '.join(roles)}"
            )
        return current_user
    
    return check_role


def require_permission(permission: str):
    """
    权限检查装饰器工厂
    Args:
        permission: 需要的权限
    Returns:
        权限检查依赖函数
    """
    async def check_permission(current_user: User = Depends(get_current_user)) -> User:
        # 这里可以实现更复杂的权限检查逻辑
        # 比如基于RBAC的权限控制
        
        # 管理员拥有所有权限
        if current_user.role == "admin":
            return current_user
        
        # 这里可以添加具体的权限检查逻辑
        # 例如从数据库查询用户权限等
        
        # 简单实现：基于角色的权限映射
        role_permissions = {
            "project_manager": [
                "project:create", "project:read", "project:update", "project:delete",
                "data_source:create", "data_source:read", "data_source:update", "data_source:delete",
                "training:create", "training:read", "training:update", "training:delete",
                "model:create", "model:read", "model:update", "model:delete"
            ],
            "developer": [
                "project:read", "project:update",
                "data_source:read", "data_source:update",
                "training:create", "training:read", "training:update",
                "model:create", "model:read", "model:update"
            ],
            "viewer": [
                "project:read", "data_source:read", "training:read", "model:read"
            ]
        }
        
        user_permissions = role_permissions.get(current_user.role, [])
        if permission not in user_permissions:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"权限不足，需要 '{permission}' 权限"
            )
        
        return current_user
    
    return check_permission


async def get_optional_current_user(
    db: AsyncSession = Depends(get_db),
    credentials: Optional[HTTPAuthorizationCredentials] = Depends(
        HTTPBearer(auto_error=False)
    )
) -> Optional[User]:
    """
    获取可选的当前用户(用于公开API)
    Args:
        db: 数据库会话
        credentials: 可选的认证凭据
    Returns:
        当前用户对象或None
    """
    if credentials is None:
        return None
    
    try:
        token = credentials.credentials
        user_id = verify_token(token)
        if user_id is None:
            return None
        
        user = await user_service.get_user_by_id(db, user_id=int(user_id))
        if user is None or not user.is_active:
            return None
        
        return user
    except Exception:
        return None


# 项目权限检查相关依赖
async def check_project_access(
    project_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> bool:
    """
    检查用户是否有项目访问权限
    Args:
        project_id: 项目ID
        current_user: 当前用户
        db: 数据库会话
    Returns:
        是否有权限
    """
    # 管理员有所有权限
    if current_user.role == "admin":
        return True
    
    # 这里需要实现具体的项目权限检查逻辑
    # 比如检查用户是否是项目所有者或项目成员
    
    # 简单实现：检查用户是否是项目所有者
    from app.repositories.project import project_repository
    project = await project_repository.get(db, id=project_id)
    
    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="项目不存在"
        )
    
    # 项目所有者有权限
    if project.owner_id == current_user.id:
        return True
    
    # 公开项目所有人都有读权限
    if project.is_public:
        return True
    
    return False


def require_project_access(project_id: int):
    """
    项目访问权限装饰器
    Args:
        project_id: 项目ID
    Returns:
        权限检查依赖函数
    """
    async def check_access(
        current_user: User = Depends(get_current_user),
        db: AsyncSession = Depends(get_db)
    ) -> User:
        has_access = await check_project_access(project_id, current_user, db)
        if not has_access:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="无权访问该项目"
            )
        return current_user
    
    return check_access